package gerenciadorDeMemoria;

import java.util.LinkedList;

import src.escalonador.Processo;

/**
 *
 * @author lucas
 */
public class MMU {

    private static LinkedList<Integer> listaFIFO ;
    private static NRU  tabelaNRU;
    private static MemoriaFisica memFisica;    
    public static int nAlgoritmoDeTroca = 0;

    public MMU(){
    	memFisica = new MemoriaFisica();
    	tabelaNRU = new NRU();
    	listaFIFO = new LinkedList<Integer>();
    }
    public static void alocaPaginas(Processo p, Pagina[] tp){
    	for (int i = 0; i < p.getTamanhoMem(); i++){
    		tp[i] = new Pagina();
    		if (!memFisica.isFull()){
    			tp[i].setFrame(memFisica.alocaFrame(p, i));
    			tp[i].setBitPresenteAusente(true);
    			listaFIFO.addLast(new Integer(tp[i].getFrame()));
    			MemoriaFisica.atualizaTextoMemoria();
    		}
    		tp[i].setIndice(i);
    	}
    	tabelaNRU.atualizaClasses();
    }

    public static void acessarPagina(Processo p, int pagina){
    	tabelaNRU.atualizaClasses();
    	if (!p.getTabelaDePaginas()[pagina].getBitPresenteAusente()){
    		pageFault(p, pagina);
    		p.getTabelaDePaginas()[pagina].setBitPresenteAusente(true);
    	}
    	if (p.colocaEspera()){
			p.getTabelaDePaginas()[pagina].setBitModified(true);
		}
    	p.getTabelaDePaginas()[pagina].setBitRecently(true);
    	p.getTabelaDePaginas()[pagina].incCountRecently();
    	MemoriaFisica.atualizaTextoMemoria();
    }
    
   
    private static void pageFault(Processo p, int pagina) {

        switch (nAlgoritmoDeTroca) {                        // qual algoritmo de troca de pagina eh?
            case 0 : trocaFIFO(p, pagina);             break;       // se for 0 entao eh o FIFO
            case 1 : trocaNRU(p,pagina);              break;       // se for 1 entao eh o NRU
            case 2 : trocaLRU(p,pagina);    break;       // se for 2 entao LRU
        }
    }


    /**
     * algoritmo de troca de paginas FIFO
     */
    private static void trocaFIFO (Processo p, int pagina) {        
    	int i = 0;
    	if (!listaFIFO.isEmpty()){
    		i = listaFIFO.removeFirst();
    	}
    	memFisica.modifyFrame(i, p, pagina);
    	p.getTabelaDePaginas()[pagina].setFrame(i);
    	listaFIFO.addLast(new Integer(i));
    }

    /**
     * algoritmo de troca de pagina NRU
     */
    private static void trocaNRU (Processo p, int pagina) {
    	int i = tabelaNRU.getFrameToSwap();
    	memFisica.modifyFrame(i, p, pagina);
    	p.getTabelaDePaginas()[pagina].setFrame(i); 
    }
    
    private static void trocaLRU(Processo p , int pagina){
    	int i = getPaginaMenosUtilizada();
    	memFisica.modifyFrame(i, p, pagina);
    	p.getTabelaDePaginas()[pagina].setFrame(i); 
    }
    
    private static int getPaginaMenosUtilizada(){
    	int indice = 0;
    	int menor = MemoriaFisica.frames[0].getProcesso().getTabelaDePaginas()[MemoriaFisica.frames[0].getPagina()].getCountRecently();
    	for (int i = 0; i < MemoriaFisica.frames.length; i++) {
    		if (MemoriaFisica.frames[i].getProcesso().getTabelaDePaginas()[MemoriaFisica.frames[i].getPagina()].getCountRecently() < menor) {
    			menor = MemoriaFisica.frames[i].getProcesso().getTabelaDePaginas()[MemoriaFisica.frames[i].getPagina()].getCountRecently();
    			indice = i;
    		}
    	}
    	return indice;
    }
}

